#ifndef SPL_WINDOW
#define SPL_WINDOW

//! Class to manage windows
class DLLEXPORT Window : public FrameWnd
{
protected:
  //! Window procedure
  virtual VOID wndProc(Event::WndProcEvent& iEvent);

  //! Occurs when the window is being created
  //! lpCreateStruct:  the window creation data
  //! Returns:
  //!      false to cancel the operation, otherwise true
  virtual VOID onCreate(Event::WndCreateEvent& iEvent);

public:
#pragma region Constructors & Destructors
  //! Window constructor
  SPLINL Window()
  {
  }
#pragma endregion

#pragma region Management
  //! Creates window
  //! hInstance:      window instance
  //! wndClass:       window class name
  //! wndName:		    window title
  //! x:		          window left bound
  //! y:              window top bound
  //! width:          window horizontal size
  //! height:         window vertical size
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! hWndParent:		  parent window handle
  //! hMenu:		      menu handle (if different from window class)
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    HINSTANCE       hInstance,
    LPCTSTR         wndClass,
    LPCTSTR         wndName,
    INT             x,
    INT             y,
    INT             width,
    INT             height,
    DWORD           dwStyle     = WS_OVERLAPPEDWINDOW,
    DWORD           dwExStyle   = 0,
    HWND            hWndParent  = NULL,
    HMENU           hMenu       = NULL)
  {
    return (mHandle = CreateWindowEx(
      dwExStyle, wndClass, wndName, dwStyle,
      x, y, width, height,
      hWndParent, hMenu,
      hInstance, this)) > 0;
  }

  //! Creates window
  //! hInstance:      window instance
  //! wndClass:       window class name
  //! wndName:		    window title
  //! wndBounds*:		  window dimentions
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! hWndParent:		  parent window handle
  //! hMenu:		      menu handle (if different from window class)
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    HINSTANCE  hInstance,
    LPCTSTR    wndClass,
    LPCTSTR    wndName,
    const Geom::BOUNDS& wndBounds,
    DWORD     dwStyle     = WS_OVERLAPPEDWINDOW,
    DWORD     dwExStyle   = 0,
    HWND      hWndParent  = NULL,
    HMENU     hMenu       = NULL)
  {
    return create(
      hInstance, wndClass, wndName,
      wndBounds.x, wndBounds.y, wndBounds.cx, wndBounds.cy,
      dwStyle, dwExStyle,
      hWndParent, hMenu);
  }

  //! Creates window
  //! wndClass:       window class name
  //! wndName:		    window title
  //! x:		          window left bound
  //! y:              window top bound
  //! width:          window horizontal size
  //! height:         window vertical size
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! hWndParent:		  parent window handle
  //! hMenu:		      menu handle (if different from window class)
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    LPCTSTR  wndClass,
    LPCTSTR  wndName,
    INT      x,
    INT      y,
    INT      width,
    INT      height,
    DWORD    dwStyle     = WS_OVERLAPPEDWINDOW,
    DWORD    dwExStyle   = 0,
    HWND     hWndParent  = NULL,
    HMENU    hMenu       = NULL)
  {
    return create(
      GetModuleHandle(NULL), wndClass, wndName,
      x, y, width, height,
      dwStyle, dwExStyle,
      hWndParent, hMenu);
  }

  //! Creates window
  //! wndName:		    window title
  //! x:		          window left bound
  //! y:              window top bound
  //! width:          window horizontal size
  //! height:         window vertical size
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! hWndParent:		  parent window handle
  //! hMenu:		      menu handle (if different from window class)
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    LPCTSTR   wndName,
    INT       x,
    INT       y,
    INT       width,
    INT       height,
    DWORD     dwStyle     = WS_OVERLAPPEDWINDOW,
    DWORD     dwExStyle   = 0,
    HWND      hWndParent  = NULL,
    HMENU     hMenu       = NULL)
  {
    return create(
      GetModuleHandle(NULL), SPL_WNDCLASS, wndName,
      x, y, width, height,
      dwStyle, dwExStyle,
      hWndParent, hMenu);
  }

  //! Creates window
  //! wndName:		    window title
  //! wndBounds*:		  window dimentions
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! hWndParent:		  parent window handle
  //! hMenu:		      menu handle (if different from window class)
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    LPCTSTR   wndName,
    const Geom::BOUNDS& wndBounds,
    DWORD     dwStyle     = WS_OVERLAPPEDWINDOW,
    DWORD     dwExStyle   = 0,
    HWND      hWndParent  = NULL,
    HMENU     hMenu       = NULL)
  {
    return create(
      wndName,
      wndBounds.x, wndBounds.y, wndBounds.cx, wndBounds.cy,
      dwStyle, dwExStyle,
      hWndParent, hMenu);
  }

  //! Creates child window
  //! hWndParent:		  parent window handle
  //! wndName:		    window title
  //! x:		          window left bound
  //! y:              window top bound
  //! width:          window horizontal size
  //! height:         window vertical size
  //! dwStyle:		    window style
  //! dwExStyle:		  window extended style
  //! Returns:        true if success, false if failure
  SPLINL BOOL create(
    HWND            hWndParent,
    LPCTSTR         wndName,
    INT             x         = 0,
    INT             y         = 0,
    INT             width     = 0,
    INT             height    = 0,
    DWORD           dwStyle   = 0,
    DWORD           dwExStyle = 0)
  {
    return create(
      SPL_CHILDCLASS, wndName,
      x, y, width, height,
      dwStyle | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
      dwExStyle,
      hWndParent, NULL);
  }

  //! Registers window class
  //! hInstance:	    handle of the application
  //! className:		  window class name
  //! classStyle:		  window class style
  //! hIcon:		      window icon handle
  //! hIconSm:		    window small icon handle
  //! hCursor:		    window cursor handle
  //! hBrush:		      window brush handle
  //! menuName:		    window menu name
  static BOOL registerClass(
    HINSTANCE hInstance,
    PCTSTR    className,
    UINT      classStyle  = 0,
    HICON     hIcon       = NULL,
    HICON     hIconSm     = NULL,
    HCURSOR   hCursor     = NULL,
    HBRUSH    hBrush      = (HBRUSH)(COLOR_WINDOW + 1),
    PCTSTR    menuName    = NULL);

  //! Registers window class
  //! className:		  window class name
  //! classStyle:		  window class style
  //! hIcon:		      window icon handle
  //! hIconSm:		    window small icon handle
  //! hCursor:		    window cursor handle
  //! hBrush:		      window brush handle
  //! menuName:		    window menu name
  static SPLINL BOOL registerClass(
    PCTSTR    className,
    UINT      classStyle  = 0,
    HICON     hIcon       = NULL,
    HICON     hIconSm     = NULL,
    HCURSOR   hCursor     = NULL,
    HBRUSH    hBrush      = (HBRUSH)(COLOR_WINDOW + 1),
    PCTSTR    menuName    = NULL)
  {
    return registerClass(
      GetModuleHandle(NULL),
      className, classStyle,
      hIcon, hIconSm,
      hCursor, hBrush,
      menuName);
  }

  //! Registers window class
  //! wndClass:	    window class to register
  static SPLINL BOOL registerClass(WNDCLASSEX *wndClass)
  {
    return RegisterClassEx(wndClass);
  }

  //! Registers window class
  //! hInstance:	    handle of the application
  //! className:		  window class name
  static SPLINL BOOL unregisterClass(HINSTANCE iInstance, PCTSTR iClassName)
  {
    return UnregisterClass(iClassName, iInstance);
  }

  //! Registers window class
  //! className:		  window class name
  static SPLINL BOOL unregisterClass(PCTSTR iClassName)
  {
    return UnregisterClass(iClassName, GetModuleHandle(NULL));
  }
#pragma endregion
};

#endif